const error = require('../error/error.js')
const config = require('../config/index.js')
const log = require('../log/log.js')

const db = uniCloud.database()

// 标准数据库对象
class Common {
  // 通过this.data._id是否存在判断该对象是否已经插入数据库
  constructor (data = {}, key = '') {
    this.set(data)
    // 获取集合名称和集合对象
    this.tableName = Common.tableNames[key]
    this.collection = db.collection(this.tableName)
  }
  
  // 数据设置
  set (data = {}) {
    if (!this.data) {
      this.data = {}
    }
    if (data && typeof data === 'object') {
      for (let key in data) {
        this.data[key] = data[key]
      }      
    }
  }
  
  // 插入检查，对于表中已有的数据，不需要重复进行数据库操作，同时在日志中有所显示
  async insertCheck () {    
    Common.log.dbLog(this.data, '即将插入数据库表' + this.tableName + '的数据')
    
    if (this.data._id) {
      // 本来就是数据库里的数据，无需重复插入
      // 暂时将此情况视为操作成功
      Common.log.dbLog('数据库中已有，无需重复插入', '对数据库表' + this.tableName + '的操作结果')
    }
  }
  
  // 更新检查
  async updateCheck (where = {}, update = {}) {
    Common.log.dbLog({ where, update }, '即将更新数据库表' + this.tableName)
    
    if (!this.data._id) {
      // 不得对一条本不在数据库中的数据进行更新
      return Common.error('DATA_ERROR')
    }
  }
  
  async deleteCheck (where = {}) {
    Common.log.dbLog({ where }, '即将删除数据库表' + this.tableName + '中的表项')
    
    if (!this.data._id) {
      // 不得对一条本不在数据库中的数据进行删除
      return Common.error('DATA_ERROR')
    }
  }
  
  // 插入
  async insert () {
    let res = Common.error('OK')
    
    await this.insertCheck()
    // 有_id字段代表已经插入
    if (this.data._id) { return res }
    
    // 订单插入数据库
    try {
      const InsertRes = await this.collection.add(this.data)
      if (!InsertRes || !InsertRes.id) {
        return Common.error('DB_ERROR', e)
      }
      // 插入成功，更新ID
      this.data._id = InsertRes.id
      res.insertRes = InsertRes
      this.dbResLog(res)
      return res
    }
    catch (e) {
      // 插入失败
      return Common.error('DB_ERROR', e)
    }
  }
  
  // 删除
  async remove () {
    let res = Common.error('OK')
    
    const query = { _id: this.data._id }
    await this.deleteCheck(query)
    
    try {      
      const removeRes = await this.collection.where(query).remove()
      
      delete this.data._id
      res.removeRes = removeRes
      this.dbResLog(res)
      return res
    }
    catch (e) {
      return Common.error('DB_ERROR', e)
    }
  }
  
  // 更新
  async update (data = {}) {
    let res = Common.error('OK')
    
    const query = { _id: this.data._id }
    await this.updateCheck(query, data)
    
    try {
      // 如果数据中有_id字段，删除，否则数据库更新会出错
      if (data.hasOwnProperty('_id')) {
        delete data._id
      }
      
      const updateRes = await this.collection.where(query).update(data)
      
      this.set(data)
      res.updateRes = updateRes
      this.dbResLog(res)
      return res
    }
    catch (e) {
      return Common.error('DB_ERROR', e)
    }
  }
  
  static getCollection (key) {
    return db.collection(Common.tableNames[key])
  }
  
  // 传入对应的collection对象，执行最后一步get，如果有sort、limit等其他限制条件，需要用此方法
  static async doGet (collection, key) {
    try {
      const res = await collection.get()
      Common.dbStaResLog(key, res)
      return res.data
    }
    catch (e) {
      return Common.error('DB_ERROR', e)
    }
  }
  
  // 直接查找，适合仅有where的情况
  static async get (key, query) {
    try {
      const collection = db.collection(Common.tableNames[key])
      const res = await collection.where(query).get()
      Common.dbStaResLog(key, res)
      return res.data
    }
    catch (e) {
      return Common.error('DB_ERROR', e)
    }
  }
  
  // 数据库表对象打印操作日志
  dbResLog (res = {}) {
    Common.log.dbLog(res, '对数据库表' + this.tableName + '的操作结果')
  }
  
  // 静态操作日志
  static dbStaResLog (key, res = {}) {
    const tableName = Common.tableNames[key]
    Common.log.dbLog(res, '对数据库表' + tableName + '的操作结果')
  }
}

Common.error = error
Common.config = config
Common.log = log
Common.tableNames = { ...Common.config.db.tableNames }

module.exports = Common